/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __PQ_Object_H__
#define __PQ_Object_H__

#include "EnginePrerequisites.h"

namespace PQEngine
{
	class Object;
	typedef std::vector<Object*> ObjectVector;
	/*This class is all events' base class.
	All events of the engine should inherit this class
	*/
	class Event
	{
	public:
		enum EventType
		{
			Event_Login_Success,
			Event_Server_Change,


			EVENT_OBJECT_CREATED,//the created object send the event type
			EVENT_OBJECT_DELETED,
			EVENT_OBJECT_SELECTED,//the created object send the event type
			EVENT_OBJECT_DESELECTED,
			EVENT_COMPONENT_ATTACHED,
			EVENT_COMPONENT_DETACHED,
			EVENT_COMPONENT_PROPERTY_UPDATED,//the component's property changed


			//Add new just above THIS LINE!
			Event_Type_Count,
		};
	public:
		Event(EventType t,Object* sender) : _type(t),_sender(sender),_handled(false)
		{
			assert(t!=Event_Type_Count);
		}

		inline void handled(bool handled) { _handled = handled; }
		inline bool isHandled(){return _handled;}
		inline Object* sender(){return _sender;}
		inline EventType type(){return _type;}

	private:
		EventType _type;
		Object* _sender;
		bool _handled;
	};

	enum ObjectType
	{
		OBJECT_TYPE_USER_DEF,//also unkown
		OBJECT_TYPE_LIGHT,

		OBJECT_TYPE_SCENE_OBJECT,
		OBJECT_TYPE_GAME_OBJECT,
		OBJECT_TYPE_TERRAIN_OBJECT,
		OBJECT_TYPE_CAMERA_OBJECT,

		OBJECT_TYPE_TERRAIN_GROUP,
		
		OBJECT_TYPE_COMPONENT_TERRAIN,
		
		OBJECT_TYPE_COMPONENT_RIGIDBODY,
		OBJECT_TYPE_COMPONENT_COLLIDER,
		OBJECT_TYPE_COMPONENT_PLANE_COLLIDER,
		OBJECT_TYPE_COMPONENT_BOX_COLLIDER,
		OBJECT_TYPE_COMPONENT_SPHERE_COLLIDER,
		OBJECT_TYPE_COMPONENT_CYLINDER_COLLIDER,
		OBJECT_TYPE_COMPONENT_CONE_COLLIDER,
		OBJECT_TYPE_COMPONENT_CAPSULE_COLLIDER,
		OBJECT_TYPE_COMPONENT_CONVEX_HULL_COLLIDER,
		

		OBJECT_TYPE_COMPONENT_TRANSFORM,
		
		OBJECT_TYPE_COMPONENT_LIGHT,
		OBJECT_TYPE_COMPONENT_MESH,
		OBJECT_TYPE_COMPONENT_SCRIPT,
	};


	/*Base class for of all objects, can be easily find
	*/
	class Object
	{
	public:
		Object(ObjectType type=OBJECT_TYPE_USER_DEF);
		virtual ~Object();
		inline ObjectType getObjectType(){return _objectType;}
		static Object* getObject(int id);
		static void removeObject(int id);
		int getId();
		static int getObjectCount();

		inline static bool isGameObject(Object* object)
		{
			if(object==0){
				return false;
			}
			ObjectType type=object->getObjectType();
			if(type==OBJECT_TYPE_GAME_OBJECT){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isSceneObject(Object* object)
		{
			if(object==0){
				return false;
			}
			ObjectType type=object->getObjectType();
			if(type==OBJECT_TYPE_SCENE_OBJECT){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isComponent(Object* object)
		{
			if(object==0){
				return false;
			}
			ObjectType type=object->getObjectType();
			if(type==OBJECT_TYPE_COMPONENT_TRANSFORM
				||type==OBJECT_TYPE_COMPONENT_MESH
				||type==OBJECT_TYPE_COMPONENT_LIGHT
				||type==OBJECT_TYPE_COMPONENT_SCRIPT
				||type==OBJECT_TYPE_COMPONENT_RIGIDBODY
				||type==OBJECT_TYPE_COMPONENT_PLANE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_BOX_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_SPHERE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CYLINDER_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CAPSULE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONVEX_HULL_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_TERRAIN){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isCollider(Object* object)
		{
			if(object==0){
				return false;
			}
			ObjectType type=object->getObjectType();
			if(type==OBJECT_TYPE_COMPONENT_PLANE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_BOX_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_SPHERE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CYLINDER_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CAPSULE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONVEX_HULL_COLLIDER){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isGameObject(ObjectType type)
		{
			if(type==OBJECT_TYPE_GAME_OBJECT){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isSceneObject(ObjectType type)
		{
			if(type==OBJECT_TYPE_SCENE_OBJECT){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isComponent(ObjectType type)
		{
			if(type==OBJECT_TYPE_COMPONENT_TRANSFORM
				||type==OBJECT_TYPE_COMPONENT_MESH
				||type==OBJECT_TYPE_COMPONENT_LIGHT
				||type==OBJECT_TYPE_COMPONENT_SCRIPT
				||type==OBJECT_TYPE_COMPONENT_RIGIDBODY
				||type==OBJECT_TYPE_COMPONENT_PLANE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_BOX_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_SPHERE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CYLINDER_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CAPSULE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONVEX_HULL_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_TERRAIN){
					return true;
			}else{
				return false;
			}
		}

		inline static bool isCollider(ObjectType type)
		{
			if(type==OBJECT_TYPE_COMPONENT_PLANE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_BOX_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_SPHERE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CYLINDER_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CAPSULE_COLLIDER
				||type==OBJECT_TYPE_COMPONENT_CONVEX_HULL_COLLIDER){
					return true;
			}else{
				return false;
			}
		}
	public:
		/*Must call it when need broadcast the evt that something happened
		@param evt The evt represent something happen
		*/
		virtual void dispatchEvent(Event* evt);

		/*Must implement it when need react the events
		*/
		virtual void handleEvent(Event* evt){}
		
		inline void ignoreEvent(Event::EventType type)
		{
			_handleEvents[type]=false;
		}

		//Need to handle the designated event
		inline void acceptEvent(Event::EventType type)
		{
			if(type>=0&&type<Event::Event_Type_Count){
				_handleEvents[type]=true;
			}
		}

		inline bool isEventAccepted(Event::EventType type)
		{
			if(type>=0&&type<Event::Event_Type_Count){
				return _handleEvents[type];
			}
			return false;
		}

	protected:
		int _id;
		ObjectType _objectType;
	private:
		static ObjectVector _objects;
		bool _handleEvents[Event::Event_Type_Count];//is event Need handled array

	};
}
#endif
